package com.yuehuanghun.admin.core.config.util;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.yuehuanghun.admin.core.config.DataScope;
import com.yuehuanghun.admin.core.domain.SysDept;
import com.yuehuanghun.admin.core.domain.SysRole;
import com.yuehuanghun.admin.core.domain.SysUser;
import com.yuehuanghun.admin.core.service.ISysDeptService;
import com.yuehuanghun.admin.core.service.ISysRoleService;
import com.yuehuanghun.admin.core.service.ISysUserService;
import com.yuehuanghun.framework.exception.BizException;

import cn.dev33.satoken.stp.StpUtil;

@Component
public class UserUtils {
	private static ISysUserService sysUserService;
	private static ISysRoleService sysRoleServices;
	private static ISysDeptService sysDeptService;
	private static ThreadLocal<Page<Object>> PAGING_STORE = new ThreadLocal<>();
	
	private static final LoadingCache<Object, Optional<SysUser>> CACHE = CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.MILLISECONDS).maximumSize(1000).build(new CacheLoader<Object, Optional<SysUser>>() {
		@Override
		public Optional<SysUser> load(Object key) throws Exception {
			suspendPaging();
			try {
				SysUser user;
				if(key instanceof Long) {
					user = sysUserService.getById((Long) key).orElse(null);
				} else {
					user = sysUserService.getUserByUserName(key.toString());
				}
				if(user != null) {
					user.setRoles(sysRoleServices.getRolesByUserId(user.getUserId()));
				}
				return Optional.ofNullable(user);
			} finally {
				resumePaging();
			}
		}
	});
	
	@Autowired
	private void init(ISysUserService sysUserService, ISysRoleService sysRoleServices, ISysDeptService sysDeptService) {
		UserUtils.sysUserService = sysUserService; //NOSONAR
		UserUtils.sysRoleServices = sysRoleServices; //NOSONAR
		UserUtils.sysDeptService = sysDeptService;
	}

	/** 当前会话的用户名 */
	public static String getCurrentUserName() {
		return StpUtil.getLoginIdAsString();
	}
	/** 根据用户名获取用户信息，缓存内容 */
	public static SysUser getUser(String userName) {
		if(StringUtils.isBlank(userName)) {
			return null;
		}
		try {
			Optional<SysUser> user = CACHE.get(userName);
			return user.orElse(null);
		} catch (ExecutionException e) {
			throw new BizException(e);
		}
	}
	/** 根据用户名获取用户信息，缓存内容 */
	public static SysUser getUser(Long userId) {
		if(userId == null) {
			return null;
		}
		try {
			Optional<SysUser> user = CACHE.get(userId);
			return user.orElse(null);
		} catch (ExecutionException e) {
			throw new BizException(e);
		}
	}
	/** 根据用户名获取用户的昵称 */
	public static String getUserNickName(String userName) {
		SysUser user = getUser(userName);
		return user == null ? null : user.getNickName();
	}
	/** 根据用户名获取用户的昵称 */
	public static String getUserNickName(Long userId) {
		SysUser user = getUser(userId);
		return user == null ? null : user.getNickName();
	}
	/** 用户名是否是管理员 */
	public static boolean isAdmin(String userName) {
		SysUser user = getUser(userName);
		if(user != null) {
			return user.isAdmin();
		}
		return false;
	}
	/** 当前会话用户信息 */
	public static SysUser getCurrentUser() {
		String currentUserName = getCurrentUserName();
		if(StringUtils.isNotBlank(currentUserName)) {
			return getUser(currentUserName);
		}
		return null;
	}
	/** 当前会话用户的部门ID */
	public static Long getCurrentUserDeptId() {
		SysUser user = getCurrentUser();
		return user == null ? null : user.getDeptId();
	}
	
	/** 清除指定用户名的用户缓存 */
	public static void clearCache(String userName) {
		if(StringUtils.isBlank(userName)) {
			return;
		}
		CACHE.invalidate(userName);
	}
	
	private static void suspendPaging() {
		PAGING_STORE.set(PageHelper.getLocalPage());
	}
	
	private static void resumePaging() {
		Page<Object> localPage = PAGING_STORE.get();
		if(localPage != null) {
			PageHelper.startPage(localPage.getPageNum(), localPage.getPageSize(), localPage.getOrderBy());
			PAGING_STORE.remove();
		}
	}
	
	/** 获取当前用户的数据范围数据 */
	public static DataScope getCurrentUserDataScope() {
		suspendPaging();
		try {
			return _getCurrentUserDataScope();
		} finally {
			resumePaging();
		}
	}
	
	@SuppressWarnings("unchecked")
	private static DataScope _getCurrentUserDataScope() {
		SysUser currentUser = getCurrentUser();
		if(currentUser == null) {
			return new DataScope(true, null, Collections.emptySet());
		}
		
		List<SysRole> roles = currentUser.getRoles();
		if(CollectionUtils.isEmpty(roles)) {
			return new DataScope(true, null, Collections.emptySet());
		}
		
		Set<String> dataScopes = roles.stream().map(SysRole::getDataScope).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
		
		if(dataScopes.contains(DATA_SCOPE_ALL)) {
			return new DataScope(true, null, null); //null表示所有权限
		}
		
		if(dataScopes.size() == 1 && dataScopes.contains(DATA_SCOPE_SELF)) { //只有自身数据权限时，后面将忽略DATA_SCOPE_SELF这个数据域
			return new DataScope(false, currentUser.getUserId(), Collections.emptySet());
		}
		
		if(dataScopes.contains(DATA_SCOPE_DEPT_AND_CHILD)) {
			dataScopes.remove(DATA_SCOPE_DEPT); //DATA_SCOPE_DEPT_AND_CHILD包含了DATA_SCOPE_DEPT
		}
		
		Set<Long> deptScope = new HashSet<>();
		
		for(String dataScope : dataScopes) {
			if(StringUtils.equals(dataScope, DATA_SCOPE_DEPT_AND_CHILD)) {
				Optional.ofNullable(currentUser.getDeptId()).ifPresent(deptId -> {
					List<SysDept> depts = sysDeptService.getByLambdaCriteria(p -> p.select(SysDept::getDeptId).contain(SysDept::getAncestors, ":" + deptId + ":"));
					depts.forEach(dept -> deptScope.add(dept.getDeptId()));
					deptScope.add(deptId);
				});
			} else if(StringUtils.equals(dataScope, DATA_SCOPE_DEPT)) {
				Optional.ofNullable(currentUser.getDeptId()).ifPresent(deptId -> {
					deptScope.add(deptId);
				});
			} else if(StringUtils.equals(dataScope, DATA_SCOPE_CUSTOM)) {
				List<SysDept> depts = sysDeptService.getByCriteria(p -> p.select("deptId").in("rolesRoleId", roles.stream().filter(item -> StringUtils.equals(item.getDataScope(), dataScope)).map(SysRole::getRoleId).collect(Collectors.toList())));
				deptScope.addAll(depts.stream().map(SysDept::getDeptId).collect(Collectors.toSet()));
			}
		}
		
		return new DataScope(true, currentUser.getUserId(), deptScope);
	}
	
	/**
	 * 当前会话是否有登录用户
	 * @return
	 */
	public static boolean hasLogin() {
		return StpUtil.isLogin();
	}
	
	/**
	 * 全部数据权限
	 */
	public static final String DATA_SCOPE_ALL = "1";

	/**
	 * 自定数据权限
	 */
	public static final String DATA_SCOPE_CUSTOM = "2";

	/**
	 * 部门数据权限
	 */
	public static final String DATA_SCOPE_DEPT = "3";

	/**
	 * 部门及以下数据权限
	 */
	public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";

	/**
	 * 仅本人数据权限
	 */
	public static final String DATA_SCOPE_SELF = "5";
}
